module test(
    input clk,
    input rst_n,

    output psram_clk,
    output psram_cs,
    inout [3:0] psram_dio,

    inout [15:0] sram_data,
    output [18:0] sram_addr,
    output sram_oe_n,
    output sram_wr_n,
    output sram_lb_n,
    output sram_ub_n,

    output dcmi_mclk,
    output dcmi_rest,
    input dcmi_vsync,
    output dcmi_pwdn,
    input dcmi_hsync,
    input dcmi_pclk,
    input [7:0] dcmi_data,
    output dcmi_scl,
    inout dcmi_sda,


    input rxd,
    output txd,
    output clk_test,
    output delay_clk
);
parameter CLK_FREQ=40000000;//5000000;
assign clk_test = psram_clk;
wire [31:0] addr;
wire [31:0] wdata;
wire [31:0] rdata;
wire [3:0] wstrb;
wire ready;
wire valid;
wire qpi_ready;
reg [9:0] clk_cnt;
reg inter_clk;
wire test_clk;
always @(posedge clk ) begin
    if(clk_cnt < 'd9) begin
        clk_cnt <= clk_cnt + 1'b1;
    end
    else begin
        clk_cnt <= 'd0;
    end
end
Gowin_rPLL Gowin_rPLL_u0
(
    .clkout(dcmi_mclk),
    .clkin(test_clk)
);
// always @(posedge clk ) begin
//     if(clk_cnt <= 'd4)begin
//         inter_clk <= 1'b1;
//     end
//     else begin
//         inter_clk <= 1'b0;
//     end
// end
Gowin_rPLL2 Gowin_rPLL_u2(
        .clkout(test_clk), //output clkout
        .clkoutp(delay_clk), //output clkoutp
        .clkin(clk) //input clkin
);

wire mem_valid_uart;
wire mem_ready_uart;
wire [31:0] mem_addr_uart;
wire [3:0] mem_wstrb_uart;
wire [31:0] mem_wdata_uart;
wire [31:0] mem_rdata_uart;

wire mem_valid_dcmi;
wire mem_ready_dcmi;
wire [31:0] mem_addr_dcmi;
wire [3:0] mem_wstrb_dcmi;
wire [31:0] mem_wdata_dcmi;
wire [31:0] mem_rdata_dcmi;

wire mem_valid_bus;
wire mem_ready_bus;
wire [31:0] mem_addr_bus;
wire [3:0] mem_wstrb_bus;
wire [31:0] mem_wdata_bus;
wire [31:0] mem_rdata_bus;


reg pbus_ready;
reg [31:0] pbus_rdata;
assign mem_ready_pbus = pbus_ready;
assign mem_rdata_pbus = pbus_rdata;

wire sccb_start_signal;
reg [7:0] sccb_wdata;
wire ld_wdata;
reg [7:0] wdata_len;
wire ack_error;
wire dev_ack_error;
wire [7:0] sccb_rdata;
wire sccb_rdata_vaild;
reg [7:0] sccb_rdata_len;
reg [7:0] sccb_dev_addr;
wire sccb_transfer_finish;
wire sccb_stop_signal;
wire sccb_busy;
sccb#(
    .CLK_FREQ(40000000),
    .SCCB_CLK(100000)//100khz
) sccb_u(
    .clk(test_clk),
    .rst_n(rst_n),

    .scl(dcmi_scl),
    .sda(dcmi_sda),
    .start_signal(sccb_start_signal),
    .wdata(sccb_wdata),
    .ld_wdata(ld_wdata),
    .wdata_len(wdata_len),
    .ack_error(ack_error),
    .dev_ack_error(dev_ack_error),

    .rdata(sccb_rdata),
    .rdata_vaild(sccb_rdata_vaild),
    .rdata_len(sccb_rdata_len),

    .dev_addr(sccb_dev_addr),
    .transfer_finish(sccb_transfer_finish),
    .sccb_stop_signal(sccb_stop_signal),
    .handle(sccb_busy)
);
assign sccb_start_signal = mem_valid_pbus&&(mem_addr_pbus[7:0] == 'd0)&&mem_wstrb_pbus[0]&&mem_wdata_pbus[0];
assign sccb_stop_signal = mem_valid_pbus&&(mem_addr_pbus[7:0] == 'd0)&&mem_wstrb_pbus[0]&&mem_wdata_pbus[1];
reg iic_busy_status;
reg sccb_busy_r;
always @(posedge test_clk ) begin
    sccb_busy_r <= sccb_busy;
end
wire sccb_busy_neg;
assign sccb_busy_neg = (sccb_busy_r)&&(~sccb_busy);
always @(posedge test_clk ) begin
    if(!rst_n) begin
        iic_busy_status <= 'b0;
    end
    else begin
        if(sccb_start_signal | sccb_stop_signal) begin
            iic_busy_status <= 'b1;
        end
        else if(sccb_busy_neg) begin
            iic_busy_status <= 'b0;
        end
        else begin
            iic_busy_status <= iic_busy_status;
        end
    end
end
reg [7:0] reg_wdata0;
reg [7:0] reg_wdata1;
reg [7:0] reg_wdata2;
reg [7:0] reg_wdata3;
reg [3:0] sccb_wdata_cnt;
always @(posedge test_clk ) begin
    if(!rst_n) begin
        sccb_wdata <= 'h00;
        sccb_wdata_cnt <= 'h00;
    end
    else begin
        if(sccb_start_signal)begin
            sccb_wdata <= reg_wdata0;
            sccb_wdata_cnt <= 'd0;
        end
        else if(ld_wdata) begin
            sccb_wdata_cnt <= sccb_wdata_cnt + 'b1;
        end
        case(sccb_wdata_cnt)
        'd0:begin
            sccb_wdata <= reg_wdata0;
        end
        'd1:begin
            sccb_wdata <= reg_wdata1;
        end
        'd2:begin
            sccb_wdata <= reg_wdata2;
        end
        'd3:begin
            sccb_wdata <= reg_wdata3;
        end
        endcase
    end
end
reg [7:0] sccb_rdata0;
reg [7:0] sccb_rdata1;
reg [7:0] sccb_rdata2;
reg [7:0] sccb_rdata3;

reg [3:0] sccb_rdata_cnt;
always @(posedge test_clk ) begin
    if(sccb_start_signal) begin
        sccb_rdata_cnt <= 'd0;
    end
    else begin
        if(sccb_rdata_vaild) begin
            sccb_rdata_cnt <= sccb_rdata_cnt + 1'b1;
            case(sccb_rdata_cnt)
            'd0:begin
                sccb_rdata0 <= sccb_rdata;
            end
            'd1:begin
                sccb_rdata1 <= sccb_rdata;
            end
            'd2:begin
                sccb_rdata2 <= sccb_rdata;
            end
            'd3:begin
                sccb_rdata3 <= sccb_rdata;
            end
            endcase
        end
    end
end
reg sccb_dev_error_reg;
reg sccb_ack_error_reg;
always @(posedge clk ) begin
    if(sccb_start_signal | sccb_stop_signal) begin
        sccb_dev_error_reg <= 'b0;
        sccb_ack_error_reg <= 'b0;
    end
    else begin
        sccb_dev_error_reg <= (~sccb_dev_error_reg) ? dev_ack_error : sccb_dev_error_reg;
        sccb_ack_error_reg <= (~sccb_ack_error_reg) ? ack_error : sccb_ack_error_reg;
    end
end
reg ov2640_reset;
reg ov2640_pwdn;
assign dcmi_rest = ov2640_reset;
assign dcmi_pwdn = ov2640_pwdn;

wire dcmi_start;
wire dcmi_busy;
assign dcmi_start = mem_valid_pbus&&(mem_addr_pbus[7:0] == 'h1c)&&mem_wstrb_pbus[0]&&mem_wdata_pbus[0];

reg [15:0] test_addr;
wire [31:0] test_data;

always @(posedge test_clk) begin
    pbus_ready <= 'b0;
    pbus_rdata <= 'h0000_0000_0000_0000;
    if(mem_valid_pbus &&(!mem_ready_pbus)) begin
        pbus_ready <= 'b1;
        if(mem_wstrb_pbus != 'b0000) begin
            case(mem_addr_pbus[7:0])
            'h0:begin//ctrl only write but don't store
                
            end
            'h4:begin//status only read
                
            end
            'h8:begin
                reg_wdata0[7:0] <= mem_wstrb_pbus[0] ? mem_wdata_pbus[7:0] : reg_wdata0[7:0];
                reg_wdata1[7:0] <= mem_wstrb_pbus[1] ? mem_wdata_pbus[15:8] : reg_wdata1[7:0];
                reg_wdata2[7:0] <= mem_wstrb_pbus[2] ? mem_wdata_pbus[23:16] : reg_wdata2[7:0];
                reg_wdata3[7:0] <= mem_wstrb_pbus[3] ? mem_wdata_pbus[31:24] : reg_wdata3[7:0];
            end
            'hc:begin//sccb rdata space don't write
                
            end
            'h10:begin
                sccb_dev_addr[7:0]      <= mem_wstrb_pbus[0] ? mem_wdata_pbus[7:0] : sccb_dev_addr[7:0];
                wdata_len[7:0]          <= mem_wstrb_pbus[1] ? mem_wdata_pbus[15:8] : wdata_len[7:0];
                sccb_rdata_len[7:0]     <= mem_wstrb_pbus[2] ? mem_wdata_pbus[23:16] : sccb_rdata_len[7:0];
            end
            'h14:begin
                ov2640_reset            <= mem_wstrb_pbus[0] ? mem_wdata_pbus[0] : ov2640_reset;
            end
            'h18:begin
                ov2640_pwdn            <= mem_wstrb_pbus[0] ? mem_wdata_pbus[0] : ov2640_pwdn;
            end
            'h1c:begin//ov2640 start
            end
            'h20:begin//only read
            end
            'h24:begin
                test_addr[7:0] <= mem_wstrb_pbus[0] ? mem_wdata_pbus[7:0] : test_addr[7:0];
                test_addr[15:8] <= mem_wstrb_pbus[1] ? mem_wdata_pbus[15:8] : test_addr[15:8];
            end
            endcase
        end
        else begin
            case(mem_addr_pbus[7:0])
            'h0:begin
                pbus_rdata <= 'h00_72_74_63;
            end
            'h4:begin
                pbus_rdata <= {29'h0,sccb_ack_error_reg,sccb_dev_error_reg,iic_busy_status};
            end
            'h8:begin
                pbus_rdata <= {reg_wdata3[7:0],reg_wdata2[7:0],reg_wdata1[7:0],reg_wdata0[7:0]};
            end
            'hc:begin
                pbus_rdata <= {sccb_rdata3[7:0],sccb_rdata2[7:0],sccb_rdata1[7:0],sccb_rdata0[7:0]};
            end
            'h10:begin
                pbus_rdata <= {8'h00,sccb_rdata_len[7:0],wdata_len[7:0],sccb_dev_addr[7:0]};
            end
            'h14:begin
                pbus_rdata <= {31'h0,ov2640_reset};
            end
            'h18:begin
                pbus_rdata <= {31'h0,ov2640_pwdn};
            end
            'h1c:begin
                pbus_rdata <= {31'h0,dcmi_busy};
            end
            'h20:begin
               pbus_rdata <= jpg_byte_count;
            end
            'h24:begin
                pbus_rdata <= {16'h0,test_addr[15:0]};
            end
            'h28:begin
                pbus_rdata <= test_data;
            end
            'h2c:begin
                pbus_rdata <= {31'h0,sclk};
            end
            endcase
        end
    end
end
wire sclk;
wire [31:0] jpg_byte_count;
ov2640 ov2640_u0(
    .clk(test_clk),
    .rst_n(rst_n),
    .dcmi_start(dcmi_start),
    .dcmi_busy(dcmi_busy),

    .dcmi_vsync(dcmi_vsync),
    .dcmi_hsync(dcmi_hsync),
    .dcmi_pclk(dcmi_pclk),
    .dcmi_data(dcmi_data),

    .test_data(test_data),
    .test_addr(test_addr),
    .sclk(sclk),
    
    .mem_valid(mem_valid_dcmi),
    .mem_wstrb(mem_wstrb_dcmi),
    .mem_addr(mem_addr_dcmi),
    .mem_wdata(mem_wdata_dcmi),
    .mem_rdata(mem_rdata_dcmi),
    .mem_ready(mem_ready_dcmi),
    .byte_count(jpg_byte_count)
);
mem_mux mem_mux_u(
    .clk(test_clk),
    .rst_n(rst_n),

    //master 0
    .mem_valid0(mem_valid_dcmi),
    .mem_ready0(mem_ready_dcmi),
    .mem_addr0(mem_addr_dcmi),
    .mem_wstrb0(mem_wstrb_dcmi),
    .mem_wdata0(mem_wdata_dcmi),
    .mem_rdata0(mem_rdata_dcmi),

    .mem_valid1(mem_valid_uart),
    .mem_ready1(mem_ready_uart),
    .mem_addr1(mem_addr_uart),
    .mem_wstrb1(mem_wstrb_uart),
    .mem_wdata1(mem_wdata_uart),
    .mem_rdata1(mem_rdata_uart),

    //slave 

    .mem_valid_slave(mem_valid_bus),
    .mem_ready_slave(mem_ready_bus),
    .mem_addr_slave(mem_addr_bus),
    .mem_wstrb_slave(mem_wstrb_bus),
    .mem_wdata_slave(mem_wdata_bus),
    .mem_rdata_slave(mem_rdata_bus)
);

always @(posedge clk ) begin
    inter_clk <= ~inter_clk;
end

wire mem_valid_psram;
wire mem_ready_psram;
wire [31:0] mem_addr_psram;
wire [3:0] mem_wstrb_psram;
wire [31:0] mem_wdata_psram;
wire [31:0] mem_rdata_psram;

wire mem_valid_sram;
wire mem_ready_sram;
wire [31:0] mem_addr_sram;
wire [3:0] mem_wstrb_sram;
wire [31:0] mem_wdata_sram;
wire [31:0] mem_rdata_sram;

wire mem_valid_pbus;
wire mem_ready_pbus;
wire [31:0] mem_addr_pbus;
wire [3:0] mem_wstrb_pbus;
wire [31:0] mem_wdata_pbus;
wire [31:0] mem_rdata_pbus;
slave_mem slave_mem_u0(
    .clk(test_clk),
    .rst_n(rst_n),

    .mem_valid_master(mem_valid_bus),
    .mem_ready_master(mem_ready_bus),
    .mem_addr_master(mem_addr_bus),
    .mem_wstrb_master(mem_wstrb_bus),
    .mem_wdata_master(mem_wdata_bus),
    .mem_rdata_master(mem_rdata_bus),

    .mem_valid_slave0(mem_valid_psram),
    .mem_ready_slave0(mem_ready_psram),
    .mem_addr_slave0(mem_addr_psram),
    .mem_wstrb_slave0(mem_wstrb_psram),
    .mem_wdata_slave0(mem_wdata_psram),
    .mem_rdata_slave0(mem_rdata_psram),

    .mem_valid_slave1(mem_valid_sram),
    .mem_ready_slave1(mem_ready_sram),
    .mem_addr_slave1(mem_addr_sram),
    .mem_wstrb_slave1(mem_wstrb_sram),
    .mem_wdata_slave1(mem_wdata_sram),
    .mem_rdata_slave1(mem_rdata_sram),

    .mem_valid_slave2(mem_valid_pbus),
    .mem_ready_slave2(mem_ready_pbus),
    .mem_addr_slave2(mem_addr_pbus),
    .mem_wstrb_slave2(mem_wstrb_pbus),
    .mem_wdata_slave2(mem_wdata_pbus),
    .mem_rdata_slave2(mem_rdata_pbus)
);

psram #(
    .PSRAM_CLK_FREQ(CLK_FREQ)
)psram_u0 (
    .clk(test_clk),
    .resetn(rst_n),
    
    .psram_clk(psram_clk),
    .psram_dio(psram_dio),
    .psram_cs(psram_cs),
    .qpi_ready(qpi_ready),

    .mem_addr(mem_addr_psram),
    .mem_wdata(mem_wdata_psram),
    .mem_wstrb(mem_wstrb_psram),
    .mem_rdata(mem_rdata_psram),
    .mem_ready(mem_ready_psram),
    .mem_valid(mem_valid_psram),
    .delay_clk(delay_clk)

);

sram sram_u0(
    .clk(test_clk),
    .rst_n(rst_n),

    .sram_data(sram_data),
    .sram_addr(sram_addr),
    .sram_oe_n(sram_oe_n),
    .sram_wr_n(sram_wr_n),
    .sram_lb_n(sram_lb_n),
    .sram_ub_n(sram_ub_n),

    .mem_valid(mem_valid_sram),
    .mem_wstrb(mem_wstrb_sram),
    .mem_addr(mem_addr_sram),
    .mem_wdata(mem_wdata_sram),
    .mem_rdata(mem_rdata_sram),
    .mem_ready(mem_ready_sram)
);

uart_debug #(
    .CLK_FREQ(CLK_FREQ),
    .UART_BPS(115200)
)uart_debug_u0
(
    .clk(test_clk),
    .resetn(rst_n),
    .reset_out(),

    .uart_rx(rxd),
    .uart_tx(txd),
    .mem_addr(mem_addr_uart),
    .mem_wdata(mem_wdata_uart),
    .mem_wstrb(mem_wstrb_uart),
    .mem_valid(mem_valid_uart),
    .mem_rdata(mem_rdata_uart),
    .mem_ready(mem_ready_uart),
    .halt_req(),
    .run_req(),
    .step_req(),
    .halt_signal(),
    .reg_addr(),

    .dbg_reg_write_req(),
    .dbg_reg_write_resp(),
    .dbg_reg_wdata(),
    .dbg_reg_raddr(),
    .dbg_reg_waddr(),
    .dbg_reg_data_out(),
    .dbg_csr_reg_addr(),
    .dbg_crs_reg_wr(),
    .dbg_csr_we_resp(),
    .dbg_csr_data_out(),
    .dbg_csr_data_in(),
    .cpu_reset_out()
);
endmodule